﻿using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading;
using HslCommunication.Core.Net;
using HslCommunication.LogNet;

namespace HslCommunication.Enthernet
{
	/// <summary>
	/// 一个基于异步高性能的客户端网络类，支持主动接收服务器的消息
	/// </summary>
	/// <remarks>
	/// 详细的使用说明，请参照博客<a href="http://www.cnblogs.com/dathlin/p/7697782.html">http://www.cnblogs.com/dathlin/p/7697782.html</a>
	/// </remarks>
	/// <example>
	/// 此处贴上了Demo项目的服务器配置的示例代码
	/// <code lang="cs" source="TestProject\HslCommunicationDemo\Hsl\FormComplexNet.cs" region="NetComplexClient" title="NetComplexClient示例" />
	/// </example>
	// Token: 0x020000F0 RID: 240
	public class NetComplexClient : NetworkXBase
	{
		/// <summary>
		/// 实例化一个对象
		/// </summary>
		// Token: 0x06001444 RID: 5188 RVA: 0x0006929C File Offset: 0x0006749C
		public NetComplexClient()
		{
			this.session = new AppSession();
			this.ServerTime = DateTime.Now;
			this.EndPointServer = new IPEndPoint(IPAddress.Any, 0);
		}

		/// <summary>
		/// 客户端系统是否启动
		/// </summary>
		// Token: 0x170004E0 RID: 1248
		// (get) Token: 0x06001445 RID: 5189 RVA: 0x000692FA File Offset: 0x000674FA
		// (set) Token: 0x06001446 RID: 5190 RVA: 0x00069302 File Offset: 0x00067502
		public bool IsClientStart { get; set; }

		/// <summary>
		/// 重连接失败的次数
		/// </summary>
		// Token: 0x170004E1 RID: 1249
		// (get) Token: 0x06001447 RID: 5191 RVA: 0x0006930B File Offset: 0x0006750B
		// (set) Token: 0x06001448 RID: 5192 RVA: 0x00069313 File Offset: 0x00067513
		public int ConnectFailedCount { get; private set; }

		/// <summary>
		/// 客户端登录的标识名称，可以为ID号，也可以为登录名
		/// </summary>
		// Token: 0x170004E2 RID: 1250
		// (get) Token: 0x06001449 RID: 5193 RVA: 0x0006931C File Offset: 0x0006751C
		// (set) Token: 0x0600144A RID: 5194 RVA: 0x00069324 File Offset: 0x00067524
		public string ClientAlias { get; set; } = string.Empty;

		/// <summary>
		/// 远程服务器的IP地址和端口
		/// </summary>
		// Token: 0x170004E3 RID: 1251
		// (get) Token: 0x0600144B RID: 5195 RVA: 0x0006932D File Offset: 0x0006752D
		// (set) Token: 0x0600144C RID: 5196 RVA: 0x00069335 File Offset: 0x00067535
		public IPEndPoint EndPointServer { get; set; }

		/// <summary>
		/// 服务器的时间，自动实现和服务器同步
		/// </summary>
		// Token: 0x170004E4 RID: 1252
		// (get) Token: 0x0600144D RID: 5197 RVA: 0x0006933E File Offset: 0x0006753E
		// (set) Token: 0x0600144E RID: 5198 RVA: 0x00069346 File Offset: 0x00067546
		public DateTime ServerTime { get; private set; }

		/// <summary>
		/// 系统与服务器的延时时间，单位毫秒
		/// </summary>
		// Token: 0x170004E5 RID: 1253
		// (get) Token: 0x0600144F RID: 5199 RVA: 0x0006934F File Offset: 0x0006754F
		// (set) Token: 0x06001450 RID: 5200 RVA: 0x00069357 File Offset: 0x00067557
		public int DelayTime { get; private set; }

		/// <summary>
		/// 客户端启动成功的事件，重连成功也将触发此事件
		/// </summary>
		// Token: 0x1400001F RID: 31
		// (add) Token: 0x06001451 RID: 5201 RVA: 0x00069360 File Offset: 0x00067560
		// (remove) Token: 0x06001452 RID: 5202 RVA: 0x00069398 File Offset: 0x00067598
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action LoginSuccess;

		/// <summary>
		/// 连接失败时触发的事件
		/// </summary>
		// Token: 0x14000020 RID: 32
		// (add) Token: 0x06001453 RID: 5203 RVA: 0x000693D0 File Offset: 0x000675D0
		// (remove) Token: 0x06001454 RID: 5204 RVA: 0x00069408 File Offset: 0x00067608
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<int> LoginFailed;

		/// <summary>
		/// 服务器的异常，启动，等等一般消息产生的时候，出发此事件
		/// </summary>
		// Token: 0x14000021 RID: 33
		// (add) Token: 0x06001455 RID: 5205 RVA: 0x00069440 File Offset: 0x00067640
		// (remove) Token: 0x06001456 RID: 5206 RVA: 0x00069478 File Offset: 0x00067678
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<string> MessageAlerts;

		/// <summary>
		/// 在客户端断开后并在重连服务器之前触发，用于清理系统资源
		/// </summary>
		// Token: 0x14000022 RID: 34
		// (add) Token: 0x06001457 RID: 5207 RVA: 0x000694B0 File Offset: 0x000676B0
		// (remove) Token: 0x06001458 RID: 5208 RVA: 0x000694E8 File Offset: 0x000676E8
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action BeforReConnected;

		/// <summary>
		/// 当接收到文本数据的时候,触发此事件
		/// </summary>
		// Token: 0x14000023 RID: 35
		// (add) Token: 0x06001459 RID: 5209 RVA: 0x00069520 File Offset: 0x00067720
		// (remove) Token: 0x0600145A RID: 5210 RVA: 0x00069558 File Offset: 0x00067758
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<AppSession, NetHandle, string> AcceptString;

		/// <summary>
		/// 当接收到字节数据的时候,触发此事件
		/// </summary>
		// Token: 0x14000024 RID: 36
		// (add) Token: 0x0600145B RID: 5211 RVA: 0x00069590 File Offset: 0x00067790
		// (remove) Token: 0x0600145C RID: 5212 RVA: 0x000695C8 File Offset: 0x000677C8
		[DebuggerBrowsable(DebuggerBrowsableState.Never)]
		public event Action<AppSession, NetHandle, byte[]> AcceptByte;

		/// <summary>
		/// 关闭该客户端引擎
		/// </summary>
		// Token: 0x0600145D RID: 5213 RVA: 0x00069600 File Offset: 0x00067800
		public void ClientClose()
		{
			this.closed = true;
			bool isClientStart = this.IsClientStart;
			if (isClientStart)
			{
				base.Send(this.session.WorkSocket, HslProtocol.CommandBytes(2, 0, base.Token, null));
			}
			this.IsClientStart = false;
			this.thread_heart_check = null;
			this.LoginSuccess = null;
			this.LoginFailed = null;
			this.MessageAlerts = null;
			this.AcceptByte = null;
			this.AcceptString = null;
			Thread.Sleep(20);
			Socket workSocket = this.session.WorkSocket;
			if (workSocket != null)
			{
				workSocket.Close();
			}
			ILogNet logNet = base.LogNet;
			if (logNet != null)
			{
				logNet.WriteDebug(this.ToString(), "Client Close.");
			}
		}

		/// <summary>
		/// 启动客户端引擎，连接服务器系统
		/// </summary>
		// Token: 0x0600145E RID: 5214 RVA: 0x000696B0 File Offset: 0x000678B0
		public void ClientStart()
		{
			bool flag = Interlocked.CompareExchange(ref this.isConnecting, 1, 0) != 0;
			if (!flag)
			{
				new Thread(new ThreadStart(this.ThreadLogin))
				{
					IsBackground = true
				}.Start();
				bool flag2 = this.thread_heart_check == null;
				if (flag2)
				{
					this.thread_heart_check = new Thread(new ThreadStart(this.ThreadHeartCheck))
					{
						Priority = ThreadPriority.AboveNormal,
						IsBackground = true
					};
					this.thread_heart_check.Start();
				}
			}
		}

		/// <summary>
		/// 连接服务器之前的消息提示，如果是重连的话，就提示10秒等待信息
		/// </summary>
		// Token: 0x0600145F RID: 5215 RVA: 0x00069738 File Offset: 0x00067938
		private void AwaitToConnect()
		{
			bool flag = this.ConnectFailedCount == 0;
			if (flag)
			{
				Action<string> messageAlerts = this.MessageAlerts;
				if (messageAlerts != null)
				{
					messageAlerts(StringResources.Language.ConnectingServer);
				}
			}
			else
			{
				int i = 10;
				while (i > 0)
				{
					bool flag2 = this.closed;
					if (flag2)
					{
						return;
					}
					i--;
					Action<string> messageAlerts2 = this.MessageAlerts;
					if (messageAlerts2 != null)
					{
						messageAlerts2(string.Format(StringResources.Language.ConnectFailedAndWait, i));
					}
					Thread.Sleep(1000);
				}
				Action<string> messageAlerts3 = this.MessageAlerts;
				if (messageAlerts3 != null)
				{
					messageAlerts3(string.Format(StringResources.Language.AttemptConnectServer, this.ConnectFailedCount));
				}
			}
		}

		// Token: 0x06001460 RID: 5216 RVA: 0x000697F4 File Offset: 0x000679F4
		private void ConnectFailed()
		{
			int connectFailedCount = this.ConnectFailedCount;
			this.ConnectFailedCount = connectFailedCount + 1;
			Interlocked.Exchange(ref this.isConnecting, 0);
			Action<int> loginFailed = this.LoginFailed;
			if (loginFailed != null)
			{
				loginFailed(this.ConnectFailedCount);
			}
			ILogNet logNet = base.LogNet;
			if (logNet != null)
			{
				logNet.WriteDebug(this.ToString(), "Connected Failed, Times: " + this.ConnectFailedCount.ToString());
			}
		}

		// Token: 0x06001461 RID: 5217 RVA: 0x00069868 File Offset: 0x00067A68
		private OperateResult<Socket> ConnectServer()
		{
			OperateResult<Socket> operateResult = base.CreateSocketAndConnect(this.EndPointServer, 10000);
			bool flag = !operateResult.IsSuccess;
			OperateResult<Socket> result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult operateResult2 = base.SendStringAndCheckReceive(operateResult.Content, 1, this.ClientAlias);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = OperateResult.CreateFailedResult<Socket>(operateResult2);
				}
				else
				{
					Action<string> messageAlerts = this.MessageAlerts;
					if (messageAlerts != null)
					{
						messageAlerts(StringResources.Language.ConnectServerSuccess);
					}
					result = operateResult;
				}
			}
			return result;
		}

		// Token: 0x06001462 RID: 5218 RVA: 0x000698E8 File Offset: 0x00067AE8
		private void LoginSuccessMethod(Socket socket)
		{
			this.ConnectFailedCount = 0;
			try
			{
				this.session.IpEndPoint = (IPEndPoint)socket.RemoteEndPoint;
				this.session.LoginAlias = this.ClientAlias;
				this.session.WorkSocket = socket;
				this.session.HeartTime = DateTime.Now;
				this.IsClientStart = true;
				this.session.WorkSocket.BeginReceive(new byte[0], 0, 0, SocketFlags.None, new AsyncCallback(this.ReceiveCallback), this.session);
			}
			catch
			{
				ThreadPool.QueueUserWorkItem(new WaitCallback(this.ReconnectServer), null);
			}
		}

		// Token: 0x06001463 RID: 5219 RVA: 0x000699A8 File Offset: 0x00067BA8
		private void ThreadLogin()
		{
			this.AwaitToConnect();
			OperateResult<Socket> operateResult = this.ConnectServer();
			bool flag = !operateResult.IsSuccess;
			if (flag)
			{
				this.ConnectFailed();
				ThreadPool.QueueUserWorkItem(new WaitCallback(this.ReconnectServer), null);
			}
			else
			{
				this.LoginSuccessMethod(operateResult.Content);
				Action loginSuccess = this.LoginSuccess;
				if (loginSuccess != null)
				{
					loginSuccess();
				}
				Interlocked.Exchange(ref this.isConnecting, 0);
				Thread.Sleep(200);
			}
		}

		// Token: 0x06001464 RID: 5220 RVA: 0x00069A28 File Offset: 0x00067C28
		private void ReconnectServer(object obj = null)
		{
			bool flag = this.isConnecting == 1;
			if (!flag)
			{
				bool flag2 = this.closed;
				if (!flag2)
				{
					Action beforReConnected = this.BeforReConnected;
					if (beforReConnected != null)
					{
						beforReConnected();
					}
					AppSession appSession = this.session;
					if (appSession != null)
					{
						Socket workSocket = appSession.WorkSocket;
						if (workSocket != null)
						{
							workSocket.Close();
						}
					}
					this.ClientStart();
				}
			}
		}

		// Token: 0x06001465 RID: 5221 RVA: 0x00069A88 File Offset: 0x00067C88
		[DebuggerStepThrough]
		private void ReceiveCallback(IAsyncResult ar)
		{
			NetComplexClient.<ReceiveCallback>d__51 <ReceiveCallback>d__ = new NetComplexClient.<ReceiveCallback>d__51();
			<ReceiveCallback>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
			<ReceiveCallback>d__.<>4__this = this;
			<ReceiveCallback>d__.ar = ar;
			<ReceiveCallback>d__.<>1__state = -1;
			<ReceiveCallback>d__.<>t__builder.Start<NetComplexClient.<ReceiveCallback>d__51>(ref <ReceiveCallback>d__);
		}

		/// <summary>
		/// 服务器端用于数据发送文本的方法
		/// </summary>
		/// <param name="customer">用户自定义的命令头</param>
		/// <param name="str">发送的文本</param>
		// Token: 0x06001466 RID: 5222 RVA: 0x00069AC8 File Offset: 0x00067CC8
		public void Send(NetHandle customer, string str)
		{
			bool isClientStart = this.IsClientStart;
			if (isClientStart)
			{
				base.Send(this.session.WorkSocket, HslProtocol.CommandBytes(customer, base.Token, str));
			}
		}

		/// <summary>
		/// 服务器端用于发送字节的方法
		/// </summary>
		/// <param name="customer">用户自定义的命令头</param>
		/// <param name="bytes">实际发送的数据</param>
		// Token: 0x06001467 RID: 5223 RVA: 0x00069B04 File Offset: 0x00067D04
		public void Send(NetHandle customer, byte[] bytes)
		{
			bool isClientStart = this.IsClientStart;
			if (isClientStart)
			{
				base.Send(this.session.WorkSocket, HslProtocol.CommandBytes(customer, base.Token, bytes));
			}
		}

		/// <summary>
		/// 心跳线程的方法
		/// </summary>
		// Token: 0x06001468 RID: 5224 RVA: 0x00069B40 File Offset: 0x00067D40
		private void ThreadHeartCheck()
		{
			Thread.Sleep(2000);
			for (;;)
			{
				Thread.Sleep(10000);
				bool flag = !this.closed;
				if (!flag)
				{
					break;
				}
				byte[] array = new byte[16];
				BitConverter.GetBytes(DateTime.Now.Ticks).CopyTo(array, 0);
				base.Send(this.session.WorkSocket, HslProtocol.CommandBytes(1, 0, base.Token, array));
				double totalSeconds = (DateTime.Now - this.session.HeartTime).TotalSeconds;
				bool flag2 = totalSeconds > 30.0;
				if (flag2)
				{
					bool flag3 = this.isConnecting == 0;
					if (flag3)
					{
						ILogNet logNet = base.LogNet;
						if (logNet != null)
						{
							logNet.WriteDebug(this.ToString(), string.Format("Heart Check Failed int {0} Seconds.", totalSeconds));
						}
						this.ReconnectServer(null);
					}
					bool flag4 = !this.closed;
					if (flag4)
					{
						Thread.Sleep(1000);
					}
				}
			}
		}

		/// <inheritdoc />
		// Token: 0x06001469 RID: 5225 RVA: 0x00069C5A File Offset: 0x00067E5A
		public override string ToString()
		{
			return string.Format("NetComplexClient[{0}]", this.EndPointServer);
		}

		// Token: 0x040004D4 RID: 1236
		private AppSession session;

		// Token: 0x040004D5 RID: 1237
		private int isConnecting = 0;

		// Token: 0x040004D6 RID: 1238
		private bool closed = false;

		// Token: 0x040004D7 RID: 1239
		private Thread thread_heart_check = null;
	}
}
